#include <gtest/gtest.h>
#include "viml/vm.h"
#include "viml/compiler.h"

TEST(VMTest, BasicExecution) {
    viml::VM vm;
    viml::Compiler compiler;
    
    // 测试简单字节码执行
    auto bytecode = std::make_shared<viml::Bytecode>("test");
    
    // LOAD_CONST R0, K[0]  ; R0 = 42
    size_t const_idx = bytecode->add_constant(viml::Value::make_number(42.0));
    bytecode->add_instruction(viml::OpCode::LOAD_CONST, 0, static_cast<uint16_t>(const_idx));
    
    // HALT
    bytecode->add_instruction(viml::OpCode::HALT);
    
    auto result = vm.execute(bytecode);
    EXPECT_TRUE(result.is_number());
    EXPECT_EQ(result.as_number(), 42.0);
}

TEST(VMTest, ArithmeticOperations) {
    viml::VM vm;
    auto bytecode = std::make_shared<viml::Bytecode>("arithmetic_test");
    
    // LOAD_CONST R0, K[0]  ; R0 = 10
    size_t const1 = bytecode->add_constant(viml::Value::make_number(10.0));
    bytecode->add_instruction(viml::OpCode::LOAD_CONST, 0, static_cast<uint16_t>(const1));
    
    // LOAD_CONST R1, K[1]  ; R1 = 5
    size_t const2 = bytecode->add_constant(viml::Value::make_number(5.0));
    bytecode->add_instruction(viml::OpCode::LOAD_CONST, 1, static_cast<uint16_t>(const2));
    
    // ADD R2, R0, R1       ; R2 = R0 + R1 = 15
    bytecode->add_instruction(viml::OpCode::ADD, static_cast<uint8_t>(2), static_cast<uint8_t>(0), static_cast<uint8_t>(1));
    
    // MOVE R0, R2          ; R0 = R2
    bytecode->add_instruction(viml::OpCode::MOVE, static_cast<uint8_t>(0), static_cast<uint8_t>(2));
    
    // HALT
    bytecode->add_instruction(viml::OpCode::HALT);
    
    auto result = vm.execute(bytecode);
    EXPECT_TRUE(result.is_number());
    EXPECT_EQ(result.as_number(), 15.0);
}

TEST(VMTest, GlobalVariables) {
    viml::VM vm;
    auto bytecode = std::make_shared<viml::Bytecode>("global_test");
    
    // LOAD_CONST R0, K[0]    ; R0 = "test_value"
    size_t const_idx = bytecode->add_constant(viml::Value::string("test_value"));
    bytecode->add_instruction(viml::OpCode::LOAD_CONST, 0, static_cast<uint16_t>(const_idx));
    
    // STORE_GLOBAL R0, N[0] ; globals["x"] = R0
    size_t name_idx = bytecode->add_name("x");
    bytecode->add_instruction(viml::OpCode::STORE_GLOBAL, 0, static_cast<uint16_t>(name_idx));
    
    // LOAD_GLOBAL R1, N[0]  ; R1 = globals["x"]
    bytecode->add_instruction(viml::OpCode::LOAD_GLOBAL, 1, static_cast<uint16_t>(name_idx));
    
    // MOVE R0, R1           ; R0 = R1
    bytecode->add_instruction(viml::OpCode::MOVE, static_cast<uint8_t>(0), static_cast<uint8_t>(1));
    
    // HALT
    bytecode->add_instruction(viml::OpCode::HALT);
    
    auto result = vm.execute(bytecode);
    EXPECT_TRUE(result.is_string());
    EXPECT_EQ(result.as_string(), "test_value");
    
    // 验证全局变量也被正确设置
    EXPECT_TRUE(vm.has_global("x"));
    auto global_val = vm.get_global("x");
    EXPECT_TRUE(global_val.is_string());
    EXPECT_EQ(global_val.as_string(), "test_value");
}